#include <std.h>
#include <pio.h>
#include <system.h>
#include <error.h>
#include <type.h>
#include <dint.h>


typedef struct tagMOUSEDATA 
{ 
   char xover; 
   char yover; 
   char xsign; 
   char ysign; 
   char midbut; 
   char rightbut; 
   char leftbut; 
   char status; 
   char xcoord; 
   char ycoord; 
} MOUSEDATA; 

 

// get data from the mouse 
void GetMouseData( MOUSEDATA* data ); 

// commands for PS2 
#define ENABLE_PS2   0xA8 
#define KBD_STAT   0x64 
#define MOUSE      0xD4 
#define MOUSE_STREAM   0xF4 
#define MOUSE_DISABLE   0xF5 
#define KBD_CMD      0x60 
#define DISABLE_KBD   0xAD 
#define ENABLE_KBD   0xAE 

// checks the port 
void CheckPort() 
{ 
   unsigned char temp; 
   while( 1 ) 
   { 
      temp = inb( KBD_STAT ); 
      if( (  temp & 2 ) == 0 ) 
         break; 
   } 
} 

// waits for the ouse buffer to be full 
void MouseBufferFull() 
{ 
   unsigned char temp; 
   while( 1 ) 
   { 
      temp = inb( KBD_STAT ); 
      if( (  temp & 0x20 ) == 0 ) 
         break; 
   } 
} 

// checks the mouse 
char CheckMouse() 
{ 
   unsigned char temp; 
   temp = inb( KBD_STAT ); 

   if( temp & 1 ) 
      return 0; 
   else 
      return 1; 
} 

// set the ps2 bytes 
void PS2Set() 
{ 
   // mouse enabled 
   kb_wait();
   outb( KBD_STAT, ENABLE_PS2 ); 
   CheckPort(); 
} 

// waits for the mouse 
void WaitMouse() 
{ 
   outb( KBD_STAT, MOUSE ); 
   CheckPort(); 
} 

// sets the streaming mode 
void StartStream() 
{ 
   WaitMouse(); 
   outb( KBD_CMD, MOUSE_STREAM ); 
   CheckPort(); 
   CheckMouse(); 
} 

// disables the keyboard 
void DisableKeyboard() 
{ 
   outb( KBD_STAT, DISABLE_KBD ); 
   CheckPort(); 
} 

// enables the keyboard 
void EnableKeyboard() 
{ 
   outb( KBD_STAT, ENABLE_KBD ); 
   CheckPort(); 
} 

// wait for the mouse - this is in the OSFAQ (http://www.osdev.org/osfaq2) 
void MouseWait( char thetype ) 
{ 
   long timeout = 100000; 
   if( thetype == 0 ) 
   { 
      while( timeout-- ) 
      { 
         if( inb( 0x64 ) & 1 ) 
         { 
            return; 
         } 
      } 
      return; 
   } 
   if( thetype == 1 ) 
   { 
      while( timeout-- ) 
      { 
         if( ( inb( 0x64 ) & 2 ) == 0 ) 
         { 
            return; 
         } 
      } 
      return; 
   } 
} 

// get a byte from the port 
char GetByte() 
{ 
   MouseWait( 0 ); 
   char ret = inb( 0x60 ); 

   return ret; 
} 

// info 
int readable = 0; 

// data pointer 
MOUSEDATA LocalData; 

// irq handler for the mouse 
void MouseIRQ() 
{ 
   //LocalData.status = GetByte(); 
   //LocalData.xcoord = GetByte(); 
   //LocalData.ycoord = GetByte(); 
	printdev("\nMouse irq");
 //  readable = 1; 
} 

// installs the IRQ 
void InstallMouseIRQ() 
{ 
   unsigned char c;
   // enable the irq 
   MouseWait(1);
   outb( 0x64, 0x20 );
   
   MouseWait(0);
	c = inb( 0x60 ) | 2;

	MouseWait(1);
   outb( 0x64, 0x60 ); 
   
   MouseWait(1);
   outb( 0x60, c ); 

   // install the irq handler 
   request_irq( 12, MouseIRQ ); 
	enable_irq(12);
} 

// get data from the mouse 
void GetMouseData( MOUSEDATA* data ) 
{ 
   // is there data? 
   if( ! readable ) 
   { 
      // there's no data yet, so just make no movement 
      data->status = 0; 
      data->xcoord = 0; 
      data->ycoord = 0; 
       
      // go back to caller 
      return; 
   } 
    
   // disable interrupts 
	start_mono();

   // readable is false now 
   readable = 0; 

   // get the important stuff 
   LocalData.leftbut = LocalData.status & 1; 
   LocalData.rightbut = ( LocalData.status & 2 ) >> 1; 
   LocalData.midbut = ( LocalData.status & 4 ) >> 2; 
   LocalData.xsign = ( LocalData.status & 16 ) >> 4; 
   LocalData.ysign = ( LocalData.status & 32 ) >> 5; 
   LocalData.xover = ( LocalData.status & 64 ) >> 6; 
   LocalData.yover = ( LocalData.status & 128 ) >> 7; 

   // return the data 
   data = &LocalData; 
    
   // enable interrupts 
   release_mono(); 
}

//----------------------------------------mystran code-------------------------------
int KBD_wait_write() { 
    unsigned int timeout = 100000; 
    unsigned char c; 
    while(--timeout) { 
        c = inb(0x64); 
        if(!(c & 2)) { 
            return 0; 
        } 
    } 
    return -1; 
} 

int KBD_write(unsigned char byte) { 
    if(!KBD_wait_write()) { 
        outb(0x60, byte); 
        return 0; 
    } 
    else return -1; 
} 

int KBD_write_cmd(unsigned char byte) { 
    if(!KBD_wait_write()) { 
        outb(0x64, byte); 
        return 0; 
    } 
    else return -1; 
} 

int KBD_write_aux(unsigned char byte) { 
    if(KBD_write_cmd(0xD4) || KBD_write(byte)) return -1; 
    else return 0; 
} 

// return unsigned char if success, -1 if fails 
int KBD_read() { 
    unsigned int timeout = 100000; 
    unsigned char c; 
    while(--timeout) { 
        c = inb(0x64); 
        if(c & 1) { 
            c = inb(0x60); 
            return (unsigned) c; 
        } 
    } 
    return -1; 
} 

int KBD_wait_ack() { 
    unsigned int timeout = 100000; 
    while(--timeout) { 
        unsigned char c = KBD_read(); 
        if(c == 0xFA) return 0; // got ack, we're happy 

        if(!c) { 
            // if we get 0, spend some time and retry 
            int i; 
            for(i = 0; i < 1000; i++) outb(0x80,0x80); 
            continue; 
        } else { 
            printdev("console_input: 0x%2x while expecting ACK\n", c); 
            return -1; 
        } 
    } 
    return -1; 
} 

// init the mouse
static int console_mouse_imps2; 
int InitMouse() 
{ 
   if(KBD_write_cmd(0xA9) || KBD_read() != 0x00) { 
        printdev("PS/2 mouse interface test failed.\n"); 
        return -1; 
    }
	// enable PS/2 mouse 
    KBD_write_cmd(0xA8);
	{
	  // fetch command word 
        if(KBD_write_cmd(0x20)) return -1; 
        int cb = KBD_read(); 
        if(cb < 0) return -1; 
        // set bit1 (aux interrupt), 
        // store the resulting new command word 
        if(KBD_write_cmd(0x60)) return -1; 
        if(KBD_write(cb |= 0x2)) return -1; // <-- only need to set aux-int bit <--
	}
	// Send set defaults 
    if(KBD_write_aux(0xF6) || KBD_wait_ack()) return -1; 

    // Enable data reporting 
    if(KBD_write_aux(0xF4) || KBD_wait_ack()) return -1; 
	
	request_irq(12,MouseIRQ);
	enable_irq(12);
	while(1);
} 

